#
# "@(#) $Id: Ripper.py,v 1.1.1.1 2006-07-27 03:16:08 gioshe Exp $"
#
# This work is released under the GNU GPL, version 2 or later.
#
from Utils.kdeemul import *
import Utils.kdeemul
import os, time, re
from Utils.utils import *
from Utils.Paths import *
from Utils.Settings import *
from Player import *
from Encoder import *
import Utils.crushToAscii
from Utils.crushToAscii import *
#import Process
from Process import Process

debug=True

def tr(str,trans):
	res = ''
	for c in str:
		if trans.has_key(c): res = res+trans[c]
		else: res = res+c
	return res

class RipperProcess(Process):
	def __init__(self,track,index,count):
		if debug: print "ripping",track.title
		self.index = index
		self.count = count
		self.track = track
		self.settings = Settings.settings()
		title = Utils.crushToAscii.crush(self.track.title)
		title = self.cleanup(title)
		from DB.EncoderLibrary import EncoderLibrary
		tmpPath = EncoderLibrary.singleton().musicPath()
		self.wavPath = os.path.join(tmpPath,title+'.wav')
		self.track.originalLocation = self.wavPath
		Process.__init__(self)

	def cleanup(self,s):
		return tr(s,{'/':'-',' ':'_',':':'_','\\':'_','<':'(','>':')',';':'_','|':'_'})

	def endProcess(self,process):
		self.emitEvent({'Source':'Ripper','Status':'EndTrack','Track':self.track,'filePath':self.wavPath,'Index':self.index,'Count':self.count})
		Process.endProcess(self,process)

	def abortProcess(self,process):
		try: os.remove(self.wavPath)
		except: pass
		self.emitEvent({'Source':'Ripper','Status':'EndTrack','Track':self.track,'Interrupted':True,'Index':self.index,'Count':self.count})
		Process.abortProcess(self,process)

	

class ParanoiaRipperProcess(RipperProcess):
	def __init__(self,track,index,count):
		RipperProcess.__init__(self,track,index,count)
		self.CDDA_BLOCKSIZE = 2352

	def buildCommand(self):
		print "ZZZZZZZZZZZZZZZZZZZ"
		debug = True
		if debug: print "ParanoiaRipperProcess::buildCommand \n"
		self.setExecutable("nice")
		args = ['-n',str(self.settings.get("Ripper Nice",10)),"cdparanoia","-d",str(self.track.driver()),"-e",str(self.track.trackNum),self.wavPath]
		#if not Settings.settings().get('CD Error Correction',False):
		#	args.append('-Z')
		self.setArguments(args)
		self.emitEvent({'Source':'Ripper','Status':'BeginTrack','Track':self.track})
	
	def processLines(self,lines):
		debug = True
		line = lines[-1]
		if debug: print "ParanoiaRipperProcess::processLines -> ",lines
		tmp = line.split('@ ')
		if len(tmp)>1 and tmp[0]=='##: -2 [wrote] ':
			value = float(tmp[1])/self.CDDA_BLOCKSIZE*2
			currentTime = long(value*1000/75) - self.track.startTime
			self.maybeEmitEvent({'Source':'Ripper','Status':'Ripping','Track':self.track,'currentTime':currentTime,'totalTime':self.track.totalTime,'Index':self.index,'Count':self.count})
	

class CDDA2WAVRipperProcess(RipperProcess):
	def __init__(self,track,index,count):
		RipperProcess.__init__(self,track,index,count)
		self.convertLineEndings = True
		self.pattern = re.compile(r".*? (\d*?)%")

	def buildCommand(self):
		self.setExecutable("nice")
		self.setArguments(['-n',str(self.settings.get("Ripper Nice",10)),"cdda2wav","-g","-H","-dev=%s" % str(self.track.busDevice()),"-t",str(self.track.trackNum),self.wavPath])
		self.emitEvent({'Source':'Ripper','Status':'BeginTrack','Track':self.track})
	
	def processLines(self,lines):
		line = lines[-1]
		#print lines
		mo = self.pattern.match(line)
		if mo:
			currentTime = long(mo.group(1))
			self.maybeEmitEvent({'Source':'Ripper','Status':'Ripping','Track':self.track,'currentTime':currentTime,'totalTime':100,'Index':self.index,'Count':self.count})

class Ripper(QObject):
	def __init__(self):
		QObject.__init__(self)
		self.tracksToRip = []
		self.ripProcess = None
		self.settings = Settings.settings()

	def ripNextTrack(self):
		if (self.ripProcess==None or not self.ripProcess.isRunning()):
			if len(self.tracksToRip)>0:
				self.gotStatus(None,{'Source':'Ripper','Status':'Begin'})
				track = self.tracksToRip[0]
				self.ripIndex = self.ripIndex+1
				self.tracksToRip = self.tracksToRip[1:]
				print "launching ripper for",track.title
				if self.settings.get('CD Error Correction',False):
					self.ripProcess = ParanoiaRipperProcess(track,self.ripIndex,self.ripTotal)
				else:
					self.ripProcess = CDDA2WAVRipperProcess(track,self.ripIndex,self.ripTotal)
				QObject.connect(self.ripProcess,PYSIGNAL("done"),self.endRipTrack)
				QObject.connect(self.ripProcess,PYSIGNAL("status"),self.gotStatus)
				self.ripProcess.run()
			else:
				print "I think I'm done ripping"
				self.gotStatus(None,{'Source':'Ripper','Status':'End','Interrupted':False})
				action = Settings.settings().get('CD Insertion Action','show')
				if action=='importAndEject':
					from CDLibrary import CDLibraries
					CDLibraries.singleton().eject()
		else:
			print "ripping is busy!"

	def endRipTrack(self,process):
		if not process.interrupted:
			try:
				filePath = process.wavPath
				if os.path.exists(filePath):
					Encoder.singleton().encodeTrack(process.track)
				else:
					print "skipping",filePath
			except: pass
			self.ripProcess = None
			self.ripNextTrack()
			
	def gotStatus(self,process,status):
		#print status
		if status.has_key('Track'):
			status['Track'].setRipStatus(status)
		self.emit(PYSIGNAL('status'),(status,None))
	
	def ripTrack(self,track):
		self.ripTracks([track])

	def ripTracks(self,tracks):
		#print "ripping ",tracks
		if len(tracks)>0:
			if len(self.tracksToRip)==0:
				self.ripTotal = 0
				self.ripIndex =0
			self.tracksToRip.extend(tracks)
			self.ripTotal = self.ripTotal+len(tracks)
			self.ripNextTrack()
	
	def isRipping(self):
		if len(self.tracksToRip)>0: return True
		if self.ripProcess and self.ripProcess.isRunning(): return True
		return False

	def killRipper(self):
		self.tracksToRip = []
		if self.ripProcess:
			self.ripProcess.kill()
			self.ripProcess = None
			self.gotStatus(None,{'Source':'Ripper','Status':'End','Interrupted':True})
	
	def static_singleton():
		global _ripperSingleton
		if _ripperSingleton==None:
			_ripperSingleton = Ripper()
		return _ripperSingleton

	singleton = staticmethod(static_singleton)

	def static_killCurrentRipper():
		Ripper.singleton().killRipper()
	killCurrentRipper = staticmethod(static_killCurrentRipper)
	
_ripperSingleton = None
